// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraPawn.h"

#include "GameFramework/Controller.h"
#include "LyraLogChannels.h"
#include "Net/UnrealNetwork.h"
#include "UObject/ScriptInterface.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraPawn)

class FLifetimeProperty;
class UObject;

/**
 * 构造函数
 */
ALyraPawn::ALyraPawn(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer) // 调用父类构造函数
{
}

/**
 * 获取生命周期复制属性
 */
void ALyraPawn::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 调用父类方法

	DOREPLIFETIME(ThisClass, MyTeamID); // 复制我的团队ID
}

/**
 * 预初始化组件
 */
void ALyraPawn::PreInitializeComponents()
{
	Super::PreInitializeComponents(); // 调用父类方法
}

/**
 * 结束游戏
 */
void ALyraPawn::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason); // 调用父类方法
}

/**
 * 被控制器拥有时调用
 */
void ALyraPawn::PossessedBy(AController* NewController)
{
	const FGenericTeamId OldTeamID = MyTeamID; // 获取旧团队ID

	Super::PossessedBy(NewController); // 调用父类方法

	// 获取当前团队ID并监听未来变化
	if (ILyraTeamAgentInterface* ControllerAsTeamProvider = Cast<ILyraTeamAgentInterface>(NewController)) // 获取作为团队提供者的控制器
	{
		MyTeamID = ControllerAsTeamProvider->GetGenericTeamId(); // 设置我的团队ID
		ControllerAsTeamProvider->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnControllerChangedTeam); // 添加团队改变动态委托
	}
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 取消拥有时调用
 */
void ALyraPawn::UnPossessed()
{
	AController* const OldController = GetController(); // 获取旧控制器

	// 停止监听旧控制器的变化
	const FGenericTeamId OldTeamID = MyTeamID; // 获取旧团队ID
	if (ILyraTeamAgentInterface* ControllerAsTeamProvider = Cast<ILyraTeamAgentInterface>(OldController)) // 获取作为团队提供者的控制器
	{
		ControllerAsTeamProvider->GetTeamChangedDelegateChecked().RemoveAll(this); // 移除所有团队改变委托
	}

	Super::UnPossessed(); // 调用父类方法

	// 确定之后新的团队ID应该是什么
	MyTeamID = DetermineNewTeamAfterPossessionEnds(OldTeamID); // 确定拥有结束后的新团队ID
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 设置通用团队ID
 */
void ALyraPawn::SetGenericTeamId(const FGenericTeamId& NewTeamID)
{
	if (GetController() == nullptr) // 如果控制器为空
	{
		if (HasAuthority()) // 如果有权限
		{
			const FGenericTeamId OldTeamID = MyTeamID; // 获取旧团队ID
			MyTeamID = NewTeamID; // 设置新团队ID
			ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
		}
		else // 否则
		{
			UE_LOG(LogLyraTeams, Error, TEXT("You can't set the team ID on a pawn (%s) except on the authority"), *GetPathNameSafe(this)); // 记录错误日志
		}
	}
	else // 否则
	{
		UE_LOG(LogLyraTeams, Error, TEXT("You can't set the team ID on a possessed pawn (%s); it's driven by the associated controller"), *GetPathNameSafe(this)); // 记录错误日志
	}
}

/**
 * 获取通用团队ID
 */
FGenericTeamId ALyraPawn::GetGenericTeamId() const
{
	return MyTeamID; // 返回我的团队ID
}

/**
 * 获取团队索引改变委托
 */
FOnLyraTeamIndexChangedDelegate* ALyraPawn::GetOnTeamIndexChangedDelegate()
{
	return &OnTeamChangedDelegate; // 返回团队改变委托
}

/**
 * 控制器改变团队时调用
 */
void ALyraPawn::OnControllerChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam)
{
	const FGenericTeamId MyOldTeamID = MyTeamID; // 获取我的旧团队ID
	MyTeamID = IntegerToGenericTeamId(NewTeam); // 设置我的新团队ID
	ConditionalBroadcastTeamChanged(this, MyOldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 我的团队ID复制时调用
 */
void ALyraPawn::OnRep_MyTeamID(FGenericTeamId OldTeamID)
{
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
}